﻿#include "PyFITKSEAShell.h"
#include "FITKSEASubSysShellPlate.h"
#include "FITKSEASubSysShellCurved.h"
#include "FITKAcousticsDiscModel.h"
#include "FITKAcousticsSEAModel.h"
#include "FITKAcousticsDiscNodeList.h"
#include "FITKSEASubSysGeoProp.h"
#include "FITK_Kernel/FITKCore/FITKAbstractDataManagerPrivate.h"


namespace Acoustics
{
    PyFITKSEAShell::PyFITKSEAShell(const QString& name)
    {
        //获取子系统管理器
        Acoustics::FITKAcousticsDiscModel* disc = Acoustics::FITKAcousticsDiscModel::GetDiscModelFromFrame();
        if (!disc)return;
        Acoustics::FITKAcousticsSEAModel* model = disc->getSEAModel();
        if (!model)return;
        Acoustics::FITKAcousticsSEASubSysManager* manager = model->getSEASubSysManager();
        if (!manager)return;
        //获取对象
        Acoustics::FITKAbstractSEASubSys* absSys = manager->getDataByName(name);
        if (!absSys)return;
        _shellObject = dynamic_cast<Acoustics::FITKAbstractSEASubSysShell*>(absSys);
    }

    int PyFITKSEAShell::getShellID()
    {
        if (_shellObject) return _shellObject->getDataObjectID();
        return -1;
    }

    bool PyFITKSEAShell::addPoint(int pointId, int pointType)
    {
        //判断类型是否存在
        if (pointType <= Acoustics::FITKAbstractSEASubSysWithNodes::None || pointType > Acoustics::FITKAbstractSEASubSysWithNodes::Finish)
            return false;
        //获取节点管理器
        Acoustics::FITKAcousticsDiscModel* discModel = Acoustics::FITKAcousticsDiscModel::GetDiscModelFromFrame();
        if (!discModel)return false;
        Acoustics::FITKAcousticsDiscNodeList* discNodesList = discModel->getNodes();
        if (!discNodesList)return false;
        //判断id是否存在
        if (!discNodesList->getNodeByID(pointId))return false;
        //添加点
        Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode point{ pointId, (Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNodeType)pointType };
        _points.append(point);
        return true;
    }

    QString PyFITKSEAShell::getName()
    {
        if (_shellObject)
            return _shellObject->getDataObjectName();
        return QString();
    }

    bool PyFITKSEAShell::setName(const QString& name)
    {
        //空字符直接返回
        if (name == ""||!_shellObject)return false;
        //获取子系统管理器
        Acoustics::FITKAcousticsDiscModel* disc = Acoustics::FITKAcousticsDiscModel::GetDiscModelFromFrame();
        if (!disc)return false;
        Acoustics::FITKAcousticsSEAModel* model = disc->getSEAModel();
        if (!model)return false;
        Acoustics::FITKAcousticsSEASubSysManager* manager = model->getSEASubSysManager();
        if (!manager)return false;

        //获取名称-查重处理
        if (manager->getDataByName(name) && _shellObject->getDataObjectName() != name)return false;

        _shellObject->setDataObjectName(name);
        return true;
    }

    bool PyFITKSEAShell::createPlate()
    {
        if (_points.size() < 3) return false;

        _shellObject = new Acoustics::FITKSEASubSysPlateShell();
        _shellObject->setNodes(_points);
        //QString name = this->ckeckNameFromMgr("Flat Plate");
        //_shellObject->setDataObjectName(name);

        return creatModel(_shellObject);
    }

    bool PyFITKSEAShell::createSinglyCurvedShell()
    {
        if (_points.size() < 8) return false;

        _shellObject = new Acoustics::FITKSEASubSysSinglyCurvedShell();
        _shellObject->setNodes(_points);
        QString name = this->ckeckNameFromMgr("Singly Curved Shell");
        _shellObject->setDataObjectName(name);

        return creatModel(_shellObject);
    }

    bool PyFITKSEAShell::createDoublyCurvedShell(int numRing)
    {
        if (numRing <= 0 || _points.size() < (numRing * 3 + 1)) return false;
        if ((_points.size() - 1) % numRing != 0) return false;

        Acoustics::FITKSEASubSysDoublyCurvedShell* shellData = new Acoustics::FITKSEASubSysDoublyCurvedShell();
        shellData->setNumberOfRing(numRing);
        shellData->setNodes(_points);
        _shellObject = shellData;
        //QString name = this->ckeckNameFromMgr("Double Curved Shell");
        //_shellObject->setDataObjectName(name);

        return creatModel(shellData);
    }

    bool PyFITKSEAShell::setDamping(int type, const QString & damping)
    {
        if (!_shellObject || damping == "" || type < 1 || type>3 ||!_spectraMgr) return false;

        //只要调用该函数，就将阻尼设置为开启
        _shellObject->setFromUserSpectraState(true);

        if (_spectraMgr == nullptr) return false;
        Core::FITKAbstractDataObject* obj = _spectraMgr->getDataObjectByName(damping);
        if (obj == nullptr) return false;
        int id = obj->getDataObjectID();

        if (type == 1) {
            _shellObject->setFlexureSpectraID(id);
        }
        else if (type == 2) {
            _shellObject->setExtensionSpectraID(id);
        }
        else if (type == 3) {
            _shellObject->setShearSpectraID(id);
        }
        return true;
    }

    bool PyFITKSEAShell::creatModel(Acoustics::FITKAbstractSEASubSysShell * shellData)
    {
        //数据对象只有点的数据时，需要更新三角网格
        if (!shellData->updateTriMesh()) return false;

        //更新几何属性
        shellData->updateGeoProp();

        //添加板到子系统管理器
        Acoustics::FITKAcousticsDiscModel* disc = Acoustics::FITKAcousticsDiscModel::GetDiscModelFromFrame();
        if (!disc)return false;
        Acoustics::FITKAcousticsSEAModel* model = disc->getSEAModel();
        if (!model)return false;
        Acoustics::FITKAcousticsSEASubSysManager* manager = model->getSEASubSysManager();
        if (!manager)return false;
        manager->appendDataObj(shellData);

        return true;
    }

    QString PyFITKSEAShell::ckeckNameFromMgr(QString name)
    {
        Acoustics::FITKAcousticsDiscModel* discModel = Acoustics::FITKAcousticsDiscModel::GetDiscModelFromFrame();
        if (!discModel)return name;
        Acoustics::FITKAcousticsSEAModel* seaModel = discModel->getSEAModel();
        if (!seaModel)return name;
        Acoustics::FITKAcousticsSEASubSysManager* subSysMgr = seaModel->getSEASubSysManager();
        if (!subSysMgr) return name;

        return subSysMgr->checkName(name);
    }

    void PyFITKSEAShell::forbiddenDamping()
    {
        if (!_shellObject) return;
        _shellObject->setFromUserSpectraState(false);
    }

    bool PyFITKSEAShell::setNCT(int NCT, double Covered, const QString & NCTtypeName)
    {
        if (!_shellObject || !_nctMgr) return false;
        if (NCT < 0 || Covered < 0) return false;
        if (Covered > 100) Covered = 100;

        Core::FITKAbstractDataObject* spec = _nctMgr->getDataObjectByName(NCTtypeName);
        if (spec == nullptr && NCTtypeName!="") return false;
        int id = -1;
        if ( spec ) id = spec->getDataObjectID();

        if (NCT == 0)
        {
            _shellObject->setInsideNCTCoveredArea(Covered);
            if(id != -1)_shellObject->setInsideNCTID(id);
        }
        else
        {
            _shellObject->setOutsideNCTCoveredArea(Covered);
            if (id != -1)_shellObject->setOutsideNCTID(id);
        }
        return true;
    }

    bool PyFITKSEAShell::setPhysicalProp(const QString & Prop)
    {
        if (!_shellObject || Prop == "" || !_propMgr) return false;

        Core::FITKAbstractDataObject* data = _propMgr->getDataObjectByName(Prop);
        /**********需判断类型data************/
        if (data == nullptr) return false;
        int id = data->getDataObjectID();

        _shellObject->setPropSection(id);
        return true;
    }

    bool PyFITKSEAShell::setEffRadiationDimensions(double area, double perimeter)
    {
        if (!_shellObject || area < 0 || perimeter < 0) return false;

        _shellObject->setEffRadiationAreaMagnification(area);
        _shellObject->setEffRadiationPerimeterMagnification(perimeter);
        return true;
    }

    bool PyFITKSEAShell::setSEAMatrixSolution(int type, bool isSolution)
    {
        if (!_shellObject || type<1 || type>3)return false;
        if (type == 1)
            _shellObject->setFlexureInSEAMatrixSolution(isSolution);
        else if (type == 2)
            _shellObject->setExtensionInSEAMatrixSolution(isSolution);
        else if (type == 3)
            _shellObject->setShearInSEAMatrixSolution(isSolution);
        return true;
    }

    bool PyFITKSEAShell::setModalDensity(int type, bool isModalDensity, QString modalDensity)
    {
        if (!_shellObject || type < 1 || type > 3||!_spectraMgr)return false;

        Core::FITKAbstractDataObject* data = _spectraMgr->getDataObjectByName(modalDensity);
        /**********需判断类型data************/
        if (data == nullptr && modalDensity != "") return false;
        int id = -1;
        if (data) id = data->getDataObjectID();

        if (type == 1) {
            _shellObject->setFlexureModelDensityState(isModalDensity);
            if (id != -1)_shellObject->setFlexureModelDensityID(id);
        }
        else if (type == 2) {
            _shellObject->setExtensionModelDensityState(isModalDensity);
            if (id != -1)_shellObject->setExtensionModelDensityID(id);
        }
        else if (type == 3) {
            _shellObject->setShearModelDensityState(isModalDensity);
            if (id != -1)_shellObject->setShearModelDensityID(id);
        }
        return true;
    }

    bool PyFITKSEAShell::setFlexureCorrectionSDP(bool is, double length, double width)
    {
        if (!_shellObject) return false;
        _shellObject->setFlexureCorrectionSDP(is);

        if(length < 0 && abs(-1 - length)>1e-64) return false;
        if(width < 0 && abs(-1 - width)>1e-64) return false;

        _shellObject->setFlexureSDPLengthMagnification(length);
        _shellObject->setFlexureSDPWidthMagnification(width);

        return true;
    }

    bool PyFITKSEAShell::setDampingFromNCT(bool is)
    {
        if (!_shellObject) return false;
        _shellObject->setFromNoiseControlState(is);
        return true;
    }

    QString PyFITKSEAShell::getGeometryProp()
    {
        if (!_shellObject) return "Get Physics Property Error";
        double area = _shellObject->getGeoProp()->getGeoProp(Acoustics::FITKSEASubSysGeoProp::GeoPropType::Area);
        double perimeter = _shellObject->getGeoProp()->getGeoProp(Acoustics::FITKSEASubSysGeoProp::GeoPropType::Circumference);
        QString pro = QString("Area is %1, Perimeter is %2").arg(area).arg(perimeter);
        return pro;
    }

}